namespace DotNetNuke.Entities.Modules
{
    using DotNetNuke.Common;
    using DotNetNuke.Common.Utilities;
    using DotNetNuke.Entities.Modules.Definitions;
    using DotNetNuke.Framework.Providers;
    using DotNetNuke.Modules.Admin.ResourceInstaller;
    using DotNetNuke.Services.Exceptions;
    using DotNetNuke.Services.Localization;
    using ICSharpCode.SharpZipLib.Zip;
    using Microsoft.VisualBasic;
    using Microsoft.VisualBasic.CompilerServices;
    using System;
    using System.Collections;
    using System.IO;
    using System.Xml;

    /// -----------------------------------------------------------------------------
    /// Project  : DotNetNuke
    /// Class  : PaWriter
    /// -----------------------------------------------------------------------------
    /// <summary>
    /// The PaWriter class packages a Module as a Private Assembly.
    /// </summary>
    /// <remarks>
    /// </remarks>
    /// <history>
    /// [cnurse] 01/13/2005 created
    /// </history>
    /// -----------------------------------------------------------------------------
    public class PaWriter
    {
        private ArrayList _Files;
        private string _Folder;
        private bool _IncludeSource;
        private string _Name;
        private PaLogger _ProgressLog;
        private string _ZipFile;

        public PaWriter() : this(false, "")
        {
        }

        public PaWriter(bool IncludeSource, string ZipFile)
        {
            this._ProgressLog = new PaLogger();
            this._IncludeSource = false;
            this._Files = new ArrayList();
            this._IncludeSource = IncludeSource;
            this._ZipFile = ZipFile;
        }

        private void AddFile(PaFileInfo File)
        {
            this.AddFile(File, false);
        }

        private void AddFile(PaFileInfo File, bool AllowUnsafeExtensions)
        {
            IEnumerator refObjectHelperL0=null;
            bool blnAdd = true;
            try
            {
                refObjectHelperL0 = this._Files.GetEnumerator();
                while (refObjectHelperL0.MoveNext())
                {
                    PaFileInfo objPaFileInfo = (PaFileInfo) refObjectHelperL0.Current;
                    if (objPaFileInfo.FullName == File.FullName)
                    {
                        blnAdd = false;
                        goto Label_0069;
                    }
                }
            }
            finally
            {
                if (refObjectHelperL0 is IDisposable)
                {
                    (refObjectHelperL0 as IDisposable).Dispose();
                }
            }
        Label_0069:
            if (!AllowUnsafeExtensions && (Strings.Right(File.FullName, 3).ToLower() == "dnn"))
            {
                blnAdd = false;
            }
            if (blnAdd)
            {
                this._Files.Add(File);
            }
        }

        private void AddSourceFiles(DirectoryInfo folder, string fileType, ref ZipOutputStream resourcesFile)
        {
            foreach (FileInfo sourceFile in folder.GetFiles(fileType))
            {
                string filePath = sourceFile.FullName;
                string fileName = sourceFile.Name;
                string folderName = folder.FullName.Replace(this._Folder, "");
                if (folderName != "")
                {
                    folderName = folderName + @"\";
                }
                if (folderName.StartsWith(@"\"))
                {
                    folderName = folderName.Substring(1);
                }
                FileSystemUtils.AddToZip(ref resourcesFile, filePath, fileName, folderName);
            }
        }

        private void CreateDnnManifest(DesktopModuleInfo objDesktopModule)
        {
            IEnumerator refObjectHelperL0=null;
            IEnumerator refObjectHelperL2=null;
            string filename = "";
            XmlDocument xmlManifest = new XmlDocument();
            XmlNode nodeRoot = xmlManifest.CreateElement("dotnetnuke");
            nodeRoot.Attributes.Append(XmlUtils.CreateAttribute(xmlManifest, "version", "3.0"));
            nodeRoot.Attributes.Append(XmlUtils.CreateAttribute(xmlManifest, "type", "Module"));
            XmlNode nodeFolders = xmlManifest.CreateElement("folders");
            nodeRoot.AppendChild(nodeFolders);
            XmlNode nodeFolder = xmlManifest.CreateElement("folder");
            nodeFolders.AppendChild(nodeFolder);
            this._Name = objDesktopModule.ModuleName;
            this._Folder = DotNetNuke.Common.Globals.ApplicationMapPath + @"\DesktopModules\" + objDesktopModule.FolderName;
            nodeFolder.AppendChild(XmlUtils.CreateElement(xmlManifest, "name", this._Name));
            nodeFolder.AppendChild(XmlUtils.CreateElement(xmlManifest, "friendlyname", objDesktopModule.FriendlyName));
            nodeFolder.AppendChild(XmlUtils.CreateElement(xmlManifest, "foldername", objDesktopModule.FolderName));
            nodeFolder.AppendChild(XmlUtils.CreateElement(xmlManifest, "modulename", this._Name));
            nodeFolder.AppendChild(XmlUtils.CreateElement(xmlManifest, "description", objDesktopModule.Description));
            if (objDesktopModule.Version == Null.NullString)
            {
                objDesktopModule.Version = "01.00.00";
            }
            nodeFolder.AppendChild(XmlUtils.CreateElement(xmlManifest, "version", objDesktopModule.Version));
            nodeFolder.AppendChild(XmlUtils.CreateElement(xmlManifest, "businesscontrollerclass", objDesktopModule.BusinessControllerClass));
            if (this._IncludeSource)
            {
                string resourcesFile = objDesktopModule.ModuleName + ".resources";
                this.CreateResourceFile(this._Folder + @"\" + resourcesFile);
                nodeFolder.AppendChild(XmlUtils.CreateElement(xmlManifest, "resourcefile", resourcesFile));
            }
            XmlNode nodeModules = xmlManifest.CreateElement("modules");
            nodeFolder.AppendChild(nodeModules);
            ArrayList arrModuleDefinitions = new ModuleDefinitionController().GetModuleDefinitions(objDesktopModule.DesktopModuleID);
            try
            {
                refObjectHelperL0 = arrModuleDefinitions.GetEnumerator();
                while (refObjectHelperL0.MoveNext())
                {
                    IEnumerator refObjectHelperL1=null;
                    ModuleDefinitionInfo objModuleInfo = (ModuleDefinitionInfo) refObjectHelperL0.Current;
                    XmlNode nodeModule = xmlManifest.CreateElement("module");
                    nodeModule.AppendChild(XmlUtils.CreateElement(xmlManifest, "friendlyname", objModuleInfo.FriendlyName));
                    nodeModule.AppendChild(XmlUtils.CreateElement(xmlManifest, "cachetime", objModuleInfo.DefaultCacheTime.ToString()));
                    ArrayList arrModuleControls = new ModuleControlController().GetModuleControls(objModuleInfo.ModuleDefID);
                    XmlNode nodeControls = xmlManifest.CreateElement("controls");
                    nodeModule.AppendChild(nodeControls);
                    try
                    {
                        refObjectHelperL1 = arrModuleControls.GetEnumerator();
                        while (refObjectHelperL1.MoveNext())
                        {
                            ModuleControlInfo objModuleControl = (ModuleControlInfo) refObjectHelperL1.Current;
                            XmlNode nodeControl = xmlManifest.CreateElement("control");
                            XmlUtils.AppendElement(ref xmlManifest, nodeControl, "key", objModuleControl.ControlKey, false);
                            XmlUtils.AppendElement(ref xmlManifest, nodeControl, "title", objModuleControl.ControlTitle, false);
                            XmlUtils.AppendElement(ref xmlManifest, nodeControl, "src", objModuleControl.ControlSrc, true);
                            XmlUtils.AppendElement(ref xmlManifest, nodeControl, "iconfile", objModuleControl.IconFile, false);
                            XmlUtils.AppendElement(ref xmlManifest, nodeControl, "type", objModuleControl.ControlType.ToString(), true);
                            XmlUtils.AppendElement(ref xmlManifest, nodeControl, "helpurl", objModuleControl.HelpURL, false);
                            nodeControls.AppendChild(nodeControl);
                            if (filename == "")
                            {
                                filename = this._Folder + @"\" + objDesktopModule.ModuleName + ".dnn";
                            }
                        }
                    }
                    finally
                    {
                        if (refObjectHelperL1 is IDisposable)
                        {
                            (refObjectHelperL1 as IDisposable).Dispose();
                        }
                    }
                    nodeModules.AppendChild(nodeModule);
                }
            }
            finally
            {
                if (refObjectHelperL0 is IDisposable)
                {
                    (refObjectHelperL0 as IDisposable).Dispose();
                }
            }
            this.CreateFileList();
            XmlNode nodeFiles = xmlManifest.CreateElement("files");
            nodeFolder.AppendChild(nodeFiles);
            try
            {
                refObjectHelperL2 = this._Files.GetEnumerator();
                while (refObjectHelperL2.MoveNext())
                {
                    PaFileInfo file = (PaFileInfo) refObjectHelperL2.Current;
                    XmlNode nodeFile = xmlManifest.CreateElement("file");
                    XmlUtils.AppendElement(ref xmlManifest, nodeFile, "path", file.Path, false);
                    XmlUtils.AppendElement(ref xmlManifest, nodeFile, "name", file.Name, false);
                    nodeFiles.AppendChild(nodeFile);
                }
            }
            finally
            {
                if (refObjectHelperL2 is IDisposable)
                {
                    (refObjectHelperL2 as IDisposable).Dispose();
                }
            }
            xmlManifest.AppendChild(nodeRoot);
            xmlManifest.Save(filename);
            this.AddFile(new PaFileInfo(objDesktopModule.ModuleName + ".dnn", "", this._Folder), true);
        }

        private void CreateFileList()
        {
            string assemblyName = "";
            string assemblyFolder = DotNetNuke.Common.Globals.ApplicationMapPath + "/bin";
            FileInfo[] files = new DirectoryInfo(this._Folder).GetFiles("*.??proj");
            foreach (FileInfo projFile in files)
            {
                IEnumerator refObjectHelperL0=null;
                XmlDocument xmlProject = new XmlDocument();
                xmlProject.Load(files[0].FullName);
                assemblyName = xmlProject.SelectSingleNode("//Settings").Attributes["AssemblyName"].Value;
                this.AddFile(new PaFileInfo(assemblyName + ".dll", "", assemblyFolder));
                XmlNodeList xmlFiles = xmlProject.SelectNodes("//File");
                try
                {
                    refObjectHelperL0 = xmlFiles.GetEnumerator();
                    while (refObjectHelperL0.MoveNext())
                    {
                        XmlNode xmlFile = (XmlNode) refObjectHelperL0.Current;
                        XmlAttribute attributeBuildAction = xmlFile.Attributes["BuildAction"];
                        XmlAttribute attributeDependUpon = xmlFile.Attributes["DependentUpon"];
                        bool bIncludeFile = false;
                        if (attributeBuildAction.Value == "None")
                        {
                            bIncludeFile = true;
                        }
                        if ((attributeBuildAction.Value == "Content") && (attributeDependUpon == null))
                        {
                            bIncludeFile = true;
                        }
                        if (bIncludeFile)
                        {
                            string relPath = xmlFile.Attributes["RelPath"].Value.Replace("/", @"\");
                            string path = "";
                            string name = relPath;
                            string fullPath = this._Folder;
                            if (relPath.LastIndexOf(@"\") > -1)
                            {
                                path = relPath.Substring(0, relPath.LastIndexOf(@"\"));
                                name = relPath.Replace(path + @"\", "");
                                fullPath = fullPath + @"\" + path;
                            }
                            this.AddFile(new PaFileInfo(name, path, fullPath));
                        }
                    }
                }
                finally
                {
                    if (refObjectHelperL0 is IDisposable)
                    {
                        (refObjectHelperL0 as IDisposable).Dispose();
                    }
                }
            }
            if (Directory.Exists(this._Folder + @"\App_LocalResources"))
            {
                DirectoryInfo localFolder = new DirectoryInfo(this._Folder + @"\App_LocalResources");
                foreach (FileInfo localFile in localFolder.GetFiles("*.resx"))
                {
                    this.AddFile(new PaFileInfo(localFile.Name, "App_LocalResources", localFolder.FullName));
                }
            }
            IDictionaryEnumerator refObjectHelperL1 = ProviderConfiguration.GetProviderConfiguration("data").Providers.GetEnumerator();
            while (refObjectHelperL1.MoveNext())
            {
                DictionaryEntry entry = (DictionaryEntry) refObjectHelperL1.Current;
                string strName = Conversions.ToString(entry.Key);
                Provider objProvider = (Provider) entry.Value;
                string providerName = objProvider.Name;
                string providerPath = this._Folder + @"\Providers\DataProviders\" + providerName;
                if (Directory.Exists(providerPath))
                {
                    this.AddFile(new PaFileInfo(assemblyName + "." + providerName + ".dll", "", assemblyFolder));
                    DirectoryInfo scriptFolder = new DirectoryInfo(providerPath);
                    foreach (FileInfo script in scriptFolder.GetFiles("*." + providerName))
                    {
                        this.AddFile(new PaFileInfo(script.Name, "", scriptFolder.FullName));
                    }
                }
            }
        }

        public string CreatePrivateAssembly(int DesktopModuleId)
        {
            DesktopModuleInfo objModule = new DesktopModuleController().GetDesktopModule(DesktopModuleId);
            this.ProgressLog.StartJob(string.Format(DotNetNuke.Services.Localization.Localization.GetString("LOG.PAWriter.CreateManifest"), objModule.FriendlyName));
            this.CreateDnnManifest(objModule);
            this.ProgressLog.EndJob(string.Format(DotNetNuke.Services.Localization.Localization.GetString("LOG.PAWriter.CreateManifest"), objModule.FriendlyName));
            this.ProgressLog.StartJob(string.Format(DotNetNuke.Services.Localization.Localization.GetString("LOG.PAWriter.CreateZipFile"), objModule.FriendlyName));
            this.CreateZipFile();
            this.ProgressLog.EndJob(string.Format(DotNetNuke.Services.Localization.Localization.GetString("LOG.PAWriter.CreateZipFile"), objModule.FriendlyName));
            return "";
        }

        private void CreateResourceFile(string fileName)
        {
            DirectoryInfo folder = new DirectoryInfo(this._Folder);
            ZipOutputStream resourcesFile = new ZipOutputStream(File.Create(fileName));
            resourcesFile.SetLevel(6);
            this.ParseFolder(folder, ref resourcesFile);
            this.AddFile(new PaFileInfo(fileName.Replace(this._Folder + @"\", ""), "", this._Folder));
            resourcesFile.Finish();
            resourcesFile.Close();
        }

        private string CreateZipFile()
        {
            int CompressionLevel = 9;
            string ZipFileShortName = this._Name;
            string ZipFileName = this._ZipFile;
            if (ZipFileName == "")
            {
                ZipFileName = ZipFileShortName + ".zip";
            }
            ZipFileName = DotNetNuke.Common.Globals.HostMapPath + ZipFileName;
            FileStream strmZipFile = null;
            try
            {
                this.ProgressLog.AddInfo(string.Format(DotNetNuke.Services.Localization.Localization.GetString("LOG.PAWriter.CreateArchive"), ZipFileShortName));
                strmZipFile = File.Create(ZipFileName);
                ZipOutputStream strmZipStream = null;
                try
                {
                    IEnumerator refObjectHelperL0=null;
                    strmZipStream = new ZipOutputStream(strmZipFile);
                    strmZipStream.SetLevel(CompressionLevel);
                    try
                    {
                        refObjectHelperL0 = this._Files.GetEnumerator();
                        while (refObjectHelperL0.MoveNext())
                        {
                            PaFileInfo PaFile = (PaFileInfo) refObjectHelperL0.Current;
                            FileSystemUtils.AddToZip(ref strmZipStream, PaFile.FullName, PaFile.Name, "");
                            this.ProgressLog.AddInfo(string.Format(DotNetNuke.Services.Localization.Localization.GetString("LOG.PAWriter.SavedFile"), PaFile.Name));
                        }
                        return ZipFileName;
                    }
                    finally
                    {
                        if (refObjectHelperL0 is IDisposable)
                        {
                            (refObjectHelperL0 as IDisposable).Dispose();
                        }
                    }
                }
                catch (Exception exception1)
                {
                    
                    Exception ex = exception1;
                    DotNetNuke.Services.Exceptions.Exceptions.LogException(ex);
                    this.ProgressLog.AddFailure(string.Format(DotNetNuke.Services.Localization.Localization.GetString("LOG.PAWriter.ERROR.SavingFile"), ex));
                    
                }
                finally
                {
                    if (strmZipStream != null)
                    {
                        strmZipStream.Finish();
                        strmZipStream.Close();
                    }
                }
            }
            catch (Exception exception2)
            {
                ProjectData.SetProjectError(exception2);
                Exception ex = exception2;
                DotNetNuke.Services.Exceptions.Exceptions.LogException(ex);
                this.ProgressLog.AddFailure(string.Format(DotNetNuke.Services.Localization.Localization.GetString("LOG.PAWriter.ERROR.SavingFile"), ex));
                
            }
            finally
            {
                if (strmZipFile != null)
                {
                    strmZipFile.Close();
                }
            }
            return ZipFileName;
        }

        private void ParseFolder(DirectoryInfo folder, ref ZipOutputStream resourcesFile)
        {
            this.AddSourceFiles(folder, "*.sln", ref resourcesFile);
            this.AddSourceFiles(folder, "*.??proj", ref resourcesFile);
            this.AddSourceFiles(folder, "*.cs", ref resourcesFile);
            this.AddSourceFiles(folder, "*.vb", ref resourcesFile);
            this.AddSourceFiles(folder, "*.resx", ref resourcesFile);
            IDictionaryEnumerator refObjectHelperL0 = ProviderConfiguration.GetProviderConfiguration("data").Providers.GetEnumerator();
            while (refObjectHelperL0.MoveNext())
            {
                DictionaryEntry entry = (DictionaryEntry) refObjectHelperL0.Current;
                Provider objProvider = (Provider) entry.Value;
                this.AddSourceFiles(folder, "*." + objProvider.Name, ref resourcesFile);
            }
            foreach (DirectoryInfo subfolder in folder.GetDirectories())
            {
                this.ParseFolder(subfolder, ref resourcesFile);
            }
        }

        public bool IncludeSource
        {
            get
            {
                return this._IncludeSource;
            }
            set
            {
                this._IncludeSource = value;
            }
        }

        public PaLogger ProgressLog
        {
            get
            {
                return this._ProgressLog;
            }
        }

        public string ZipFile
        {
            get
            {
                return this._ZipFile;
            }
            set
            {
                this._ZipFile = value;
            }
        }
    }
}

